package com.wesley.growth.itext7.chapter2;

import cn.hutool.core.io.FileUtil;
import com.itextpdf.io.font.constants.StandardFonts;
import com.itextpdf.kernel.colors.Color;
import com.itextpdf.kernel.colors.DeviceCmyk;
import com.itextpdf.kernel.colors.DeviceRgb;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.canvas.PdfCanvasConstants;

import javax.swing.text.StyleConstants;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * AxesCanvas
 * 文档地址：
 * https://kb.itextpdf.com/itext/chapter-2-adding-low-level-content
 *
 * @author WangPanYong
 * @since 2023/03/31 09:39
 */
public class AxesCanvas {

    /**
     * 绘制坐标
     *
     * PDF中，所有测量都以用户单位(user unit)完成。 默认情况下，一个用户单位对应一个点。 这意味着在一英寸(one inch)内有72个用户单位
     * 使用PageSize对象创建页面大小，则坐标系的原点位于页面的左下角。
     */
    void axes(File pdfFile) throws FileNotFoundException {
        PdfDocument pdf = new PdfDocument(new PdfWriter(pdfFile));
        // 页面是A4大小，旋转过后变成了横向
        PageSize ps = PageSize.A4.rotate();
        PdfPage page = pdf.addNewPage(ps);
        PdfCanvas canvas = new PdfCanvas(page);

        /**
         * concatMatrix的参数是一个3*3的变换矩阵：
         * a   b   0
         * c   d   0
         * e   f   1
         * 这个矩阵的第三列的是固定值：(0,0,1)，之所以是这样是因为我们是在二维里面操作
         */
        // 使坐标系的原点位于页面正中间。
        canvas.concatMatrix(1, 0, 0, 1, ps.getWidth() / 2, ps.getHeight() / 2);

        // Draw X axis
        canvas.moveTo(-(ps.getWidth() / 2 - 15), 0)
              .lineTo(ps.getWidth() / 2 - 15, 0)
              .stroke();
        //Draw X axis arrow
        canvas.setLineJoinStyle(PdfCanvasConstants.LineJoinStyle.ROUND)
              .moveTo(ps.getWidth() / 2 - 25, -10)
              .lineTo(ps.getWidth() / 2 - 15, 0)
              .lineTo(ps.getWidth() / 2 - 25, 10).stroke()
              .setLineJoinStyle(PdfCanvasConstants.LineJoinStyle.MITER);
        // Draw Y axis
        canvas.moveTo(0, -(ps.getHeight() / 2 - 15))
              .lineTo(0, ps.getHeight() / 2 - 15)
              .stroke();
        //Draw Y axis arrow
        // 我们用saveState()方法来保存当前的图像状态
        canvas.saveState()
              .setLineJoinStyle(PdfCanvasConstants.LineJoinStyle.ROUND)
              .moveTo(-10, ps.getHeight() / 2 - 25)
              .lineTo(0, ps.getHeight() / 2 - 15)
              .lineTo(10, ps.getHeight() / 2 - 25).stroke()
              .restoreState();
        // saveState()和restoreState()必须成对出现，而且restoreState() 不能先于savaState()

        //Draw X serif
        for (int i = -((int) ps.getWidth() / 2 - 61);
             i < ((int) ps.getWidth() / 2 - 60); i += 40) {
            canvas.moveTo(i, 5).lineTo(i, -5);
        }
        //Draw Y serif
        for (int j = -((int) ps.getHeight() / 2 - 57);
             j < ((int) ps.getHeight() / 2 - 56); j += 40) {
            canvas.moveTo(5, j).lineTo(-5, j);
        }
        canvas.stroke();

        // DeviceRgb（RGB空间，有红色、绿色和蓝色决定）和DeviceCmyk（印刷四色空间，由青色、品红、黄色和黑色）
        Color grayColor = new DeviceCmyk(0.f, 0.f, 0.f, 0.875f);
        Color greenColor = new DeviceCmyk(1.f, 0.f, 1.f, 0.176f);
        Color blueColor = new DeviceCmyk(1.f, 0.156f, 0.f, 0.118f);

        // 线条的宽度为0.5用户单位
        canvas.setLineWidth(0.5f).setStrokeColor(blueColor);
        for (int i = -((int) ps.getHeight() / 2 - 57);
             i < ((int) ps.getHeight() / 2 - 56); i += 40) {
            canvas.moveTo(-(ps.getWidth() / 2 - 15), i)
                  .lineTo(ps.getWidth() / 2 - 15, i);
        }
        for (int j = -((int) ps.getWidth() / 2 - 61);
             j < ((int) ps.getWidth() / 2 - 60); j += 40) {
            canvas.moveTo(j, -(ps.getHeight() / 2 - 15))
                  .lineTo(j, ps.getHeight() / 2 - 15);
        }
        canvas.stroke();

        // 2个用户宽度的虚线
        canvas.setLineWidth(2).setStrokeColor(greenColor)
              // 实线(dash)的长度为10个用户单位，实线之间的间隙为10个用户单位，相位(phase)为8个用户单位
              .setLineDash(10, 10, 8)
              .moveTo(-(ps.getWidth() / 2 - 15), -(ps.getHeight() / 2 - 15))
              .lineTo(ps.getWidth() / 2 - 15, ps.getHeight() / 2 - 15).stroke();

        pdf.close();
    }

    List<String> text = new ArrayList<>();

    {
        text.add("         Episode V         ");
        text.add("  THE EMPIRE STRIKES BACK  ");
        text.add("It is a dark time for the");
        text.add("Rebellion. Although the Death");
        text.add("Star has been destroyed,");
        text.add("Imperial troops have driven the");
        text.add("Rebel forces from their hidden");
        text.add("base and pursued them across");
        text.add("the galaxy.");
        text.add("Evading the dreaded Imperial");
        text.add("Starfleet, a group of freedom");
        text.add("fighters led by Luke Skywalker");
        text.add("has established a new secret");
        text.add("base on the remote ice world");
        text.add("of Hoth...");
    }

    /**
     *
     */
    void textState(File pdfFile) throws IOException {
        PdfDocument pdf = new PdfDocument(new PdfWriter(pdfFile));
        // 页面是A4大小，旋转过后变成了横向
        PageSize ps = PageSize.A4.rotate();
        PdfPage page = pdf.addNewPage(ps);
        PdfCanvas canvas = new PdfCanvas(page);
//        // 把原来在左下角的坐标系放到左上角来
//        canvas.concatMatrix(1, 0, 0, 1, 0, ps.getHeight());

        /*
        // 文字普通填充
        canvas.beginText()
              // 文本状态为等宽粗体和字体大小为14
              .setFontAndSize(PdfFontFactory.createFont(StandardFonts.COURIER_BOLD), 14)
              // 间距为字体大小的1.2倍
              .setLeading(14 * 1.2f)
              // 向右移动70个用户单位，向下移动40个用户单位，也就是(70,-40)开始显示文字
              .moveText(70, -40);

        for (String s : text) {
            // Add text and move to the next line
            canvas.newlineShowText(s);
        }
        // newlineShowText() 必须在beginText()和endText()之间，并且beginText() -> endText()之间顺序不能打乱
        canvas.endText();
         */

        // 创建一个矩形，矩形的左下角的坐标为(0,0)，宽度和高度为页面的宽度和高度，然后我们设置填充颜色为黑色
        canvas.rectangle(0, 0, ps.getWidth(), ps.getHeight())
              .setColor(DeviceRgb.BLACK, true)
              .fill();
        // 把原来在左下角的坐标系放到左上角来
        canvas.concatMatrix(1, 0, 0, 1, 0, ps.getHeight());
        // 使用Cmyk空间定义了黄色
        Color yellowColor = new DeviceCmyk(0.f, 0.0537f, 0.769f, 0.051f);
        float lineHeight = 5;
        float yOffset = -40;
        canvas.beginText()
              .setFontAndSize(PdfFontFactory.createFont(StandardFonts.COURIER_BOLD), 1)
              .setColor(yellowColor, true);

        int maxStringWidth = text.stream().map(String::length).reduce(Math::max).orElse(0);
        for (int j = 0; j < text.size(); j++) {
            String line = text.get(j);
            // xOffset变量来决定当前行的文字的起始位置
            float xOffset = ps.getWidth() / 2 - 45 - 8 * j;
            // 字体大小被定义为1个用户单位，但是我们将它与一个fontSizeCoeff相乘，这取决于文本数组中行的索引
            float fontSizeCoeff = 6 + j;
            float lineSpacing = (lineHeight + j) * j / 1.5f;
            int stringWidth = line.length();
            for (int i = 0; i < stringWidth; i++) {
                float angle = (maxStringWidth / 2 - i) / 2f;
                float charXOffset = (4 + (float) j / 2) * i;
                // a 和 d 定义了缩放比例. We'll use them to change the font size
                // c 参数定义了倾斜程度
                // x 和 y 是字符的坐标
                canvas.setTextMatrix(fontSizeCoeff, 0,
                                     angle, fontSizeCoeff / 1.5f,
                                     xOffset + charXOffset, yOffset - lineSpacing)
                      .showText(String.valueOf(line.charAt(i)));
            }
        }
        canvas.endText();

        pdf.close();
    }

    public static void main(String[] args) throws IOException {
        File dir = new File("temp");
        File pdfFile = FileUtil.createTempFile("axes_", ".pdf", dir, true);

        AxesCanvas axesCanvas = new AxesCanvas();
//        axesCanvas.axes(pdfFile);
        axesCanvas.textState(pdfFile);
        System.out.println("pdfFile = " + pdfFile.getName());
    }
}
